/****************************************************************************
 * Copyright (C) 2025 Chenyz. All rights reserved.
 *
 * @file    TinyOS_Timer.c
 *
 * @par     dependencies
 *          - TinyOS_Timer.h (Timer management definitions)
 *          - TinyOS_Task.h (Task management definitions)
 *          - TinyOS_Semaphore.h (Semaphore synchronization)
 *
 * @author  Chenyz
 *
 * @brief   Timer management module for TinyOS with following features:
 *          - One-shot and periodic timer support
 *          - Interrupt-driven and task-based timer configurations
 *          - Timer state management with lifecycle control
 *          - Thread-safe timer operations with semaphore protection
 *          - Timer callback execution with parameter passing
 *          - Timer information retrieval and lifecycle management
 *          - Integration with system tick and task scheduling
 *          - Cross-platform compatibility (bare-metal/RTOS systems)
 *
 * @version V1.0
 * @date    2025-05-23
 *
 * @note    Coding standard:
 *          - 4 spaces per indent level
 *          - Follow MISRA-C 2012 guidelines
 *          - Compiler compatibility: C99 and above
 *
 ****************************************************************************/

#include "TinyOS_Timer.h"
#include "TinyOS_Task.h"
#include "TinyOS_Semaphore.h"


#if TINYOS_ENABLE_TIMER == 1

/**
 * @brief Initializes a timer with specified parameters
 * 
 * This function configures a timer control block with timing parameters,
 * operation mode, and callback function. The timer can operate in one-shot
 * or periodic mode with configurable initial delay.
 * 
 * @param Timer Pointer to the timer structure to be initialized
 * @param StartDelayTicks Initial delay before first expiration (0 for immediate)
 * @param PeriodTicks Period for periodic timers (0 for one-shot)
 * @param TimerConfig Timer operation mode (interrupt or task context)
 * @param TimerCallbacks Callback function to execute on timer expiration
 * @param param User parameter passed to callback function
 */
void TinyOS_TimerInit(
    TinyOS_TimerType* Timer,
    uint32_t StartDelayTicks,
    uint32_t PeriodTicks,
    uint32_t TimerConfig,
    void (*TimerCallbacks)(void* param),
    void* param
)
{
    /* Initialize timer list node */
    TinyOS_NodeInit(&(Timer->LinkNode));
    
    /* Configure timer parameters */
    Timer->StartDelayTicks = StartDelayTicks;
    Timer->PeriodTicks = PeriodTicks;
    Timer->TimerConfig = TimerConfig;
    Timer->pfTimerCallbacks = TimerCallbacks;
    Timer->param = param;
    
    /* Set initial delay based on configuration */
    if(StartDelayTicks == 0)
    {
        Timer->DelayTicks = PeriodTicks;
    }
    else
    {
        Timer->DelayTicks = Timer->StartDelayTicks;
    }
       
    Timer->TimerState = TinyOS_TimerStateCreated;     
}

/**
 * @brief Activates a timer and adds it to the appropriate timer list
 * 
 * This function starts timer counting and adds it to either the interrupt
 * or task timer list based on configuration. The timer begins counting
 * down from its initial delay.
 * 
 * @param Timer Pointer to the timer structure to be started
 */
void TinyOS_TimerStart(TinyOS_TimerType* Timer)
{
    switch(Timer->TimerState)
    {
        case TinyOS_TimerStateCreated:
        case TinyOS_TimerStateStopped:
            /* Reset delay counter based on timer configuration */
            if(Timer->StartDelayTicks > 0)
            {
                Timer->DelayTicks = Timer->StartDelayTicks;
            }
            else
            {
                Timer->DelayTicks = Timer->PeriodTicks;                
            }
            
            Timer->TimerState = TinyOS_TimerStateStarted;
            
            /* Add to appropriate timer list based on configuration */
            if(Timer->TimerConfig == TINYOS_TIMER_CONFIGTYPE_INT)
            {
                /* Interrupt context timer - use critical section */
                uint32_t Stauts = TinyOS_TaskEnterCritical();  
                TinyOS_ListHeadInsert(&TimerIntList, &(Timer->LinkNode));
                TinyOS_TaskExitCritical(Stauts);  
            }
            else
            {
                /* Task context timer - use semaphore protection */
                TinyOS_SemaphoreTake(&TimerProtectSem, 0);
                TinyOS_ListHeadInsert(&TimerTaskList, &(Timer->LinkNode));
                TinyOS_SemaphoreGive(&TimerProtectSem);
            }      
            break;
        default:
            /* Ignore start requests for timers in invalid states */
            break;    
    }  
}

/**
 * @brief Stops an active timer and removes it from timer lists
 * 
 * This function halts timer counting and removes it from the active
 * timer list. The timer can be restarted later without reinitialization.
 * 
 * @param Timer Pointer to the timer structure to be stopped
 */
void TinyOS_TimerStop(TinyOS_TimerType* Timer)
{
    switch(Timer->TimerState)
    {
        case TinyOS_TimerStateStarted:
        case TinyOS_TimerStateRunning:           
            /* Remove from appropriate timer list based on configuration */
            if(Timer->TimerConfig == TINYOS_TIMER_CONFIGTYPE_INT)
            {
                /* Interrupt context timer - use critical section */
                uint32_t Stauts = TinyOS_TaskEnterCritical();  
                TinyOS_ListDeleteNode(&TimerIntList, &(Timer->LinkNode));
                TinyOS_TaskExitCritical(Stauts);  
            }
            else
            {
                /* Task context timer - use semaphore protection */
                TinyOS_SemaphoreTake(&TimerProtectSem, 0);
                TinyOS_ListDeleteNode(&TimerTaskList, &(Timer->LinkNode));
                TinyOS_SemaphoreGive(&TimerProtectSem);
            }  
            
            Timer->TimerState = TinyOS_TimerStateStopped;            
            break;
        default:
            /* Ignore stop requests for timers in invalid states */
            break;    
    }        
    
}

/**
 * @brief Permanently deletes a timer and stops its operation
 * 
 * This function stops the timer and marks it as deleted. A deleted timer
 * cannot be restarted and should not be used further.
 * 
 * @param Timer Pointer to the timer structure to be deleted
 */
void TinyOS_TimerDelete(TinyOS_TimerType* Timer)
{
    TinyOS_TimerStop(Timer);
    Timer->TimerState = TinyOS_TimerStateDeleted;
}

/**
 * @brief Retrieves current configuration and state of a timer
 * 
 * This function provides access to the timer's current parameters,
 * configuration, and operational state for monitoring and debugging.
 * 
 * @param Timer Pointer to the timer structure to query
 * @param TimerInfo Pointer to structure where timer information will be stored
 */
void TinyOS_TimerGetInfo(
    TinyOS_TimerType* Timer, 
    TinyOS_TimerInfoType* TimerInfo
)
{
    uint32_t Stauts = TinyOS_TaskEnterCritical();  	
    
    /* Copy timer configuration and state information */
    TimerInfo->PeriodTicks = Timer->PeriodTicks;
    TimerInfo->StartDelayTicks = Timer->StartDelayTicks;
    TimerInfo->TimerConfig = Timer->TimerConfig;
    TimerInfo->TimerState = Timer->TimerState;
    TimerInfo->pfTimerCallbacks = Timer->pfTimerCallbacks;
    TimerInfo->param = Timer->param;

	TinyOS_TaskExitCritical(Stauts);  
}

/**
 * @brief Processes timer list and executes expired timer callbacks
 * 
 * This internal function iterates through a timer list, decrements
 * remaining ticks, and executes callbacks for expired timers. Handles
 * both one-shot and periodic timer behavior.
 * 
 * @param TimerList Pointer to the timer list to process
 */
void TinyOS_TimerHandleList(TinyOS_ListType* TimerList)
{
    uint8_t TimerIsExpired = 0;
    TinyOS_NodeType* TempNode;
    
    /* Iterate through all timers in the specified list */
    for (
        TempNode = TimerList->HeadNode.NextNode; 
        TempNode != &(TimerList->HeadNode); 
        TempNode = TempNode->NextNode
    )
    {
        /* Convert list node to timer control block */
        TinyOS_TimerType *TempTimer = \
        TINYOS_NODE_PARENT(TempNode, TinyOS_TimerType, LinkNode);
        
        /* Check if timer has already expired or will expire this tick */
        if (TempTimer->DelayTicks == 0) 
        {
            TimerIsExpired = 1;
        }
        else 
        {
            /* Decrement timer counter and check for expiration */
            TempTimer->DelayTicks--;
            if (TempTimer->DelayTicks == 0) 
            {
                TimerIsExpired = 1;
            }
        }
        
        /* Handle timer expiration if detected */
        if (TimerIsExpired) 
        {
            /* Execute timer callback with state management */
            TempTimer->TimerState = TinyOS_TimerStateRunning;
            TempTimer->pfTimerCallbacks(TempTimer->param);
            TempTimer->TimerState = TinyOS_TimerStateStarted;
            
            /* Handle periodic vs one-shot timer behavior */
            if (TempTimer->PeriodTicks > 0) 
            {
                /* Periodic timer - reset counter for next period */
                TempTimer->DelayTicks = TempTimer->PeriodTicks;
            } 
            else 
            {
                /* One-shot timer - remove from active list */
                TinyOS_ListDeleteNode(TimerList, &TempTimer->LinkNode);
                TempTimer->TimerState = TinyOS_TimerStateStopped;
            }
        }
    }   
}

/**
 * @brief Processes interrupt-context timers from system tick handler
 * 
 * This function is called from the system tick interrupt to handle
 * timers configured for interrupt context execution. Signals task
 * context timers for later processing.
 */
void TinyOS_TimerNotifyFromInt(void)
{ 
    uint32_t Stauts = TinyOS_TaskEnterCritical();  
    
    /* Process interrupt-context timers */
	TinyOS_TimerHandleList(&TimerIntList);
	
	TinyOS_TaskExitCritical(Stauts);	
	
	/* Signal task context for timer processing */
	TinyOS_SemaphoreGive(&TimerTickSem);
}

/**
 * @brief Initializes the timer management subsystem
 * 
 * This function sets up the timer infrastructure including timer lists
 * and synchronization mechanisms. Must be called before using any timer functions.
 */
void TinyOS_TimerModuleInit(void)
{
    /* Initialize timer management lists */
    TinyOS_ListInit(&TimerIntList);
    TinyOS_ListInit(&TimerTaskList);    
    
    /* Initialize synchronization mechanisms */
    TinyOS_SemaphoreInit(&TimerProtectSem, 1, 1);    /* Binary semaphore for list protection */
    TinyOS_SemaphoreInit(&TimerTickSem, 0, 0);       /* Counting semaphore for tick notification */
}

#endif

